<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

    <script>
        function sleep(duration) {
            let start = Date.now()
            while (start + duration > Date.now()) { } //2000后结束
        }

        function progress() {
            console.log('progress')
            requestAnimationFrame(progress)
        }
        // requestAnimationFrame(progress)
        let channel = new MessageChannel();
        let activeFrameTime = 1000 / 60; //16.6
        // 每帧截止时间
        let frameDeadline;
        // 待执行任务
        let pendingCallback;
        // 剩余时间
        let timeRemaining = () => frameDeadline - performance.now()
        channel.port2.onmessage = function () {
            let currentTime = performance.now();
            // 帧的截至时间小于当前时间，过期

            if (pendingCallback) {
                pendingCallback({ timeRemaining });
            }

        }

        window.requestIdleCallback = (callback, options) => {
            requestAnimationFrame((rafTime) => {

                // performance.timing.navigationStart + performance.now() = Date.now()
                // performance.timing.navigationStart 页面开始渲染的时间戳
                // performance.now() 页面加载完成据现在的时间
                // rafTime: 每帧开始时间据页面开始渲染的时间
                console.log('rafTime', rafTime)
                console.log('performance', performance.now())
                // 每帧开始的时间+16.6，就是每帧截止的时间
                frameDeadline = rafTime + activeFrameTime
                pendingCallback = callback
                // 发消息之后，相当于添加一个宏任务，浏览器有空才会去执行
                channel.port1.postMessage('hello')
            })
        }

        const works = [
            () => {
                console.log('A1开始');
                sleep(2);
                console.log('A1结束');
            },
            () => {
                console.log('B1开始');
                sleep(2);
                console.log('B1结束');
            }, () => {
                console.log('C1开始');
                sleep(2);
                console.log('C1结束');
            }, () => {
                console.log('C2开始');
                sleep(2);
                console.log('C2结束');
            }, () => {
                console.log('B2开始');
                sleep(2);
                console.log('B2结束');
            }, () => {
                console.log('B3开始');
                sleep(2);
                console.log('B3结束');
            }, () => {
                console.log('B4开始');
                sleep(2);
                console.log('B4结束');
            },

        ]
        requestIdleCallback(workLoop)

        // 循环执行工作
        function workLoop(deadline) {
            console.log('本帧的剩余时间', parseInt(deadline.timeRemaining())) //浏览器无事可做时 idleCallBack 的时间会延长为50ms
            while (deadline.timeRemaining() > 0 && works.length > 0) {
                performUnitOfWork();
            }
            if (works.length > 0) {
                console.log(`只剩下${deadline.timeRemaining()}, 时间片已经到期了, 等待下次调度`)
                // 每帧的空闲时间之行
                requestIdleCallback(workLoop)
            }
        }

        function performUnitOfWork() {
            let work = works.shift(); //取出工作数组中的第一个元素
            work();
        }
    </script>
</body>

</html>